#include "qtch/log.h"
#include "insert.h"
#include "util.h"
#include "table.h"

#include <set>

namespace qtch {
namespace orm {

static Logger::ptr logger = QTCH_LOG_NAME("orm");


Insert::Insert(std::shared_ptr<Table> table) {
    m_table = table;
}

bool Insert::init(const tinyxml2::XMLElement& node) {
    if(strcasecmp(node.Name(),"insert")){
        return false;
    }

    if(!node.Attribute("id")){
        QTCH_LOG_ERROR(logger) << "insert id not exists";
        return false;
    }
    m_id = node.Attribute("id");
    QTCH_LOG_DEBUG(logger) << "insert init id=" << m_id;

    const tinyxml2::XMLNode * label = node.FirstChild();
    while(label){
        Label::ptr label_ptr = Label::Create(*label);
        if(!label_ptr){
            QTCH_LOG_ERROR(logger) << "insert init faile,insert id=" << m_id;
            return false;
        }
        std::vector<OrmParameter::ptr> temp = label_ptr->getBindVec();
        for(size_t i=0;i<temp.size();++i){
            if(temp[i]->getType()!=Column::Type::TYPE_NULL){
                continue;
            }
            std::vector<Column::ptr> colVec = m_table->getCols();
            int flag = 0;
            for(size_t j=0;j<colVec.size();j++){
                if(colVec[j]->getName()==temp[i]->getName()){
                    temp[i]->setType(Column::Type::TYPE_TABLE);
                    flag =1;
                    break;
                }
            }
            if(flag){
                m_usingEntiry = true;
            }else{
                QTCH_LOG_ERROR(logger) << "insert id=" << m_id << " init param name=" << temp[i]->getName() \
                            <<" faile by unkonw type";
                return false;
            }
        }
        m_label.push_back(label_ptr);
        label = label->NextSibling();
    }
    return true;
}

std::string Insert::gen_inc() {
    std::stringstream ss;
    ss << "int ";
    ss << gen_ParameterList();
    return ss.str();
}

std::string Insert::gen_src() {
    std::stringstream ss;
    ss << "int ";
    ss << m_table->getClassDaoName() << "::";
    ss << gen_ParameterList();
    ss << " {" << std::endl;
    ss << "    qtch::IStmt::ptr __orm_stmt;" << std::endl;
    ss << "    std::stringstream __orm_sql;" << std::endl;
    ss << "    int __orm_paramNum = 0;" << std::endl;
    ss << "    __orm_paramNum++;" << std::endl;
    ss << "    __orm_paramNum--;" << std::endl;
    ss << std::endl;
    for(size_t i = 0; i < m_label.size(); ++i){
        ss << m_label[i]->gen(m_table);
        ss << std::endl;
    }
    ss << "    return __orm_stmt->execute();" << std::endl;
    ss << "}";
    return ss.str();
}

std::string Insert::gen_ParameterList() {
    std::stringstream ss;

    ss << GetAsClassName(m_id) << "(";
    
    std::vector<OrmParameter::ptr> parmVec;
    for(size_t i=0;i<m_label.size();++i){
        std::vector<OrmParameter::ptr> temp = m_label[i]->getBindVec();
        for(size_t j=0;j<temp.size();j++){
            parmVec.push_back(temp[j]);
        }
    }
    std::set<std::string> paramNameSet;
    if(m_usingEntiry){
        paramNameSet.insert("__orm_entiry");
        ss << m_table->getClassName()<< "::ptr __orm_entiry, ";
    }


    for(size_t i=0;i<parmVec.size();++i){
        if(paramNameSet.count(parmVec[i]->getName())==1){
            continue;
        }
        if(parmVec[i]->getType()==Column::Type::TYPE_NULL
         ||parmVec[i]->getType()==Column::Type::TYPE_TABLE){
            continue;
        }
        ss << Column::TypeToString(parmVec[i]->getType()) << " ";
        ss << parmVec[i]->getName() << ", ";

    }
    ss << "qtch::IDB::ptr __orm_conn)";

    return ss.str();
}

std::string Insert::gen_default_inc() {
    return "";
}

std::string Insert::gen_default_src() {
    return "";
}



}
}